#ifndef InclusionGuard_SoundPotMainAudioEffect_h
#define InclusionGuard_SoundPotMainAudioEffect_h



// Include VST SDK headers

#include "public.sdk/source/vst2.x/audioeffectx.h"
#include "public.sdk/source/vst2.x/aeffeditor.h"


// Include other things

#include "juce.h"
#include "SoundPotMainGui.h"
#include "SoundPotUtilities.h"
#include "SoundPotSoundHost.h"
#include "SoundPotInstrumentResponder.h"
#include "SoundPotInstrumentDao.h"
#include "SoundPotVstSound.h"



namespace SoundPot
{
	// This has to be declared because of the circular relationship with MainGui
	class MainGui;
	

	// No idea

	static VoidArray activePlugins;


	// Finally our AudioEffectX

	class MainAudioEffect  : public AudioEffectX,
		private Timer,
		public ChangeBroadcaster,
		public InstrumentResponder
#if JUCE_LINUX
		, public Thread
#endif


	{
	public:
		MainAudioEffect (audioMasterCallback audioMaster);

		~MainAudioEffect();

		// InstrumentResponder methods

		float getCurrentSampleRate();
		int getMaxBlockSize();


		// A(udio)Effect(X) methods

		void open();

		void close();

		bool getEffectName (char* name);

		bool getVendorString (char* text);

		bool getProductString (char* text);

		VstInt32 getVendorVersion();

		VstPlugCategory getPlugCategory();

		VstInt32 canDo (char* text);

		bool keysRequired();

		VstInt32 processEvents (VstEvents* events);

		void processReplacing (float** inputs, float** outputs, VstInt32 numSamples);

		void resume();

		void suspend();

		VstInt32 getProgram();

		void setProgram (VstInt32 program);

		void setProgramName (char* name);

		void getProgramName (char* name);

		bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text);

		float getParameter (VstInt32 index);

		void setParameter (VstInt32 index, float value);

		void getParameterDisplay (VstInt32 index, char* text);

		void getParameterName (VstInt32 index, char* text);

		VstInt32 getChunk (void** data, bool isPreset);

		VstInt32 setChunk (void* data, VstInt32 byteSize, bool isPreset);

		VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt);

		
		// Additional methods

		bool JUCE_CALLTYPE getCurrentPositionInfo (CurrentPositionInfo& info);

		
		// This is called regularly by Timer thread (right?) - always try idle, sometimes chunkMemory gets cleared.

		void timerCallback();

		void tryMasterIdle();

		void doIdleCallback();

#if JUCE_LINUX
		void run ();
#endif

		void deleteEditor();

		MainGui* createEditor();


		void createEditorComp();


		void resizeHostWindow (int newWidth, int newHeight);

		const CriticalSection& JUCE_CALLTYPE getCallbackLock() const throw() { return callbackLock; }



		juce_UseDebuggingNewOperator

	private:

		// The SoundHost
		SoundHost* soundHost;


		// Temporary

		VstSound* sound1;
		Sound* sound2;
		InstrumentDao* instrumentDao;

		// Todo: Make this unnecessary
		friend class MainGui;
		
		/// Thread lock
		CriticalSection callbackLock;


		/// Holds the sample rate
		double sampleRate;

		/// Holds the maximum block size
		int blockSize;

		/// Holds the concrete number of input / output channels
		int numInputChannels, numOutputChannels;

		/// Holds the active editor gui, if existing
		MainGui* activeEditor;

		/// Saves the current position
		// Helgo: Optional
		CurrentPositionInfo lastPosInfo;

		/// Used to restore editor bounds
		int lastUIWidth, lastUIHeight;

		/// Holds effect state for a while so that the host can save it
		juce::MemoryBlock chunkMemory;

		/// Gets a time stamp as soon as the host asks for chunk
		// Helgo: Maybe optional
		uint32 chunkMemoryTime;

		/// Holds the AEffect editor bounds prepared for the host
		ERect editorSize;

		/// Holds new midi events
		MidiBuffer midiEvents;

		/// Holds events which shall be sent to the host
		// Helgo: Optional
		VstEvents* outgoingEvents;

		/// ?
		int outgoingEventSize;

		/// Holds the suspended state
		bool isProcessing;

		/// ?
		void ensureOutgoingEventSize (int numEvents);

		/// Gets the host name
		// Helgo: Fuck it to hell!
		const String getHostName();


		/// Holds the host window
	#if JUCE_MAC
		WindowRef hostWindow;
	#elif JUCE_LINUX
		Window hostWindow;
	#else
		HWND hostWindow;
	#endif
	};
}
#endif